package com.partner.partnerback.utils;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.connection.RedisConnectionCommands;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
* redis 工具类
**/
@SuppressWarnings(value = {"unchecked", "rawtypes"})
@Component
@Slf4j
public class RedisUtils {
private static RedisTemplate staticRedisTemplate;

private final RedisTemplate redisTemplate;

public RedisUtils(RedisTemplate redisTemplate) {
    // 防止key中文乱码
    redisTemplate.setKeySerializer(new StringRedisSerializer()); // key的序列化类型

    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
                                       ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
    redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); // value的序列化类型
    redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
    redisTemplate.afterPropertiesSet();
    this.redisTemplate = redisTemplate;
}

@PostConstruct
public void initRedis() {
    // 初始化设置 静态redis对象，方便后续操作数据
    staticRedisTemplate = redisTemplate;
}

/**
* 缓存基本的对象，Integer、String、实体类等
*
* @param key   缓存的键值
* @param value 缓存的值
*/
public static <T> void setCacheObject(final String key, final T value) {
    staticRedisTemplate.opsForValue().set(key, value);
}

        /**
* 缓存基本的对象，Integer、String、实体类等
*
* @param key      缓存的键值
* @param value    缓存的值
* @param timeout  时间
* @param timeUnit 时间颗粒度
*/
public static <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
    staticRedisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}

public static <T> void setCacheObject(final String key, final T value, final int timeoutInSecond) {
	setCacheObject(key, value, timeoutInSecond, TimeUnit.SECONDS);
}

  /**
  * 设置有效时间
  *
  * @param key     Redis键
  * @param timeout 超时时间
  * @return true=设置成功；false=设置失败
  */
  public static boolean expire(final String key, final long timeout) {
  	return expire(key, timeout, TimeUnit.SECONDS);
  }

  /**
  * 设置有效时间
  *
  * @param key     Redis键
  * @param timeout 超时时间
  * @param unit    时间单位
  * @return true=设置成功；false=设置失败
  */
  public static boolean expire(final String key, final long timeout, final TimeUnit unit) {
  	return Boolean.TRUE.equals(staticRedisTemplate.expire(key, timeout, unit));
  }

 /**
 * 获取单个key的过期时间
 * @param key
 * @return
 */
  public static Long getExpireTime(final String key) {
    return staticRedisTemplate.getExpire(key);
  }

  /**
  * 获得缓存的基本对象。
  *
  * @param key 缓存键值
  * @return 缓存键值对应的数据
  */
  public static <T> T getCacheObject(final String key) {
  ValueOperations<String, T> operation = staticRedisTemplate.opsForValue();
  	return operation.get(key);
  }

  /**
  * 删除单个对象
  *
  * @param key
  */
  public static boolean deleteObject(final String key) {
  	return Boolean.TRUE.equals(staticRedisTemplate.delete(key));
  }


    /**
     * 发送ping命令
     * redis 返回pong
     */
    public static void ping() {
        String res = (String) staticRedisTemplate.execute(RedisConnectionCommands::ping);
        log.info("Redis ping ==== {}", res);
    }


}
